﻿using System;
using System.Collections;
using System.Reflection;
namespace DataAccess
{
   
        public class ReflectionUtil
        {
            ReflectionUtil()
            {

            }

            public static bool InstanceOf<T>(Object instance)
            {
                return typeof(T).IsInstanceOfType(instance);
            }

            #region Assembly Loading

            /// <summary>
            /// Checks if the assembly is loaded in the current AppDomain
            /// </summary>
            /// <param name="assemblyName">The full assembly name to search for.</param>
            /// <returns>true if the assembly is loaded otherwise false</returns>
            public static bool AssemblyLoaded(String assemblyName)
            {
                foreach (Assembly ass in AppDomain.CurrentDomain.GetAssemblies())
                {
                    if (ass.GetName().Name.Equals(assemblyName))
                        return true;
                }
                return false;
            }

            /// <summary>
            /// Loads the assembly into the current AppDomain
            /// </summary>
            /// <param name="assemblyName">The full assembly name to load into the current AppDomain</param>
            /// <returns>The loaded assembly</returns>
            public static Assembly LoadAssembly(String assemblyName)
            {
                return Assembly.Load(assemblyName);
            }

            #endregion

            #region Activate Classes

            /// <summary>
            /// Attempts to create an instance by calling the default constructor of the class.
            /// </summary>
            /// <param name="className">The full class name of the class to activate.</param>
            /// <param name="assemblyName">The full assembly name containing the class to activate.</param>
            /// <returns>The activated class</returns>
            /// <remarks>The class name must be the full name eg. MyNamespace.ClassName</remarks>
            public static Object CreateLocalInstance(String className, String assemblyName)
            {
                Object obj = null;
                try
                {
                    Assembly ass = LoadAssembly(assemblyName);
                    obj = Activator.CreateInstance(ass.GetType(className, true, true));
                }
                catch
                {
                }
                return obj;
            }

            /// <summary>
            /// Attempts to create an instance by calling the default constructor of the class.
            /// </summary>
            /// <typeparam name="T">The Type to return.</typeparam>
            /// <param name="className">The full class name of the class to activate.</param>
            /// <param name="assemblyName">The full assembly name containing the class to activate.</param>
            /// <returns>The activate class casted to type T</returns>
            /// <remarks>The class name must be the full name eg. MyNamespace.ClassName</remarks>
            public static T CreateLocalInstance<T>(String className, String assemblyName)
            {
                return (T)CreateLocalInstance(className, assemblyName);
            }

            public static T CreateLocalInstance<T>(Type type)
            {
                return (T)Activator.CreateInstance(type);
            }

            /// <summary>
            /// Attempts to create an instance by calling the default constructor of the class.
            /// </summary>
            /// <typeparam name="T">The Type to return.</typeparam>
            /// <param name="className">The class to activate.</param>
            /// <returns>The activate class casted to type T</returns>
            /// <remarks>The class name must be the full name eg. MyNamespace.ClassName</remarks>
            public static T CreateLocalInstance<T>(String className)
            {
                return (T)Activator.CreateInstance(Type.GetType(className));
            }

            #endregion

            #region Type Getters

            /// <summary>
            /// Returns the Type represented by the assemblyName and className
            /// </summary>
            /// <param name="assemblyName">The full assembly name to check for the Type</param>
            /// <param name="className">The full class name of the Type to get.</param>
            /// <returns>The Type if found otherwise null.</returns>
            /// <remarks>The class name must be the full name eg. MyNamespace.ClassName</remarks>
            public static Type GetType(String assemblyName, String className)
            {
                Type t = null;
                try
                {
                    t = Type.GetType(className, true, true);
                }
                catch
                {
                    try
                    {
                        Assembly ass = LoadAssembly(assemblyName);
                        t = ass.GetType(className, true, true);
                    }
                    catch
                    {
                        t = null;
                    }
                }
                return t;
            }

            #endregion

            public static Object GetPropertyValue(Object rootInstance, String propertyPath)
            {
                if (rootInstance == null)
                    return null;

                Type t = rootInstance.GetType();
                if (String.IsNullOrEmpty(propertyPath))
                    return null;

                int dotIdx = propertyPath.IndexOf('.');
                if (dotIdx <= 0)
                {
                    return SafeGetProperty(t, propertyPath).GetValue(rootInstance, null);
                }

                String prop = propertyPath.Substring(0, dotIdx);
                return GetPropertyValue(SafeGetProperty(t, prop).GetValue(rootInstance, null), propertyPath.Substring(dotIdx + 1));
            }

            private static PropertyInfo SafeGetProperty(Type t, string property)
            {
                try
                {
                    return t.GetProperty(property);
                }
                catch (AmbiguousMatchException)
                {
                    return t.GetProperty(property, BindingFlags.Public | BindingFlags.DeclaredOnly | BindingFlags.Instance);
                }
                return null;
            }

            public static T GetPropertyValue<T>(Object rootInstance, String propertyPath)
            {
                if (rootInstance == null)
                    return default(T);

                Type t = rootInstance.GetType();
                if (String.IsNullOrEmpty(propertyPath))
                    return default(T);

                int dotIdx = propertyPath.IndexOf('.');
                if (dotIdx <= 0)
                    return (T)SafeGetProperty(t, propertyPath).GetValue(rootInstance, null);

                String prop = propertyPath.Substring(0, dotIdx);
                return GetPropertyValue<T>(SafeGetProperty(t, prop).GetValue(rootInstance, null), propertyPath.Substring(dotIdx + 1));
            }

            public static Type GetPropertyType(Type rootType, String propertyPath)
            {
                PropertyInfo pi;
                if (rootType == null)
                    throw new ArgumentNullException("rootType", "root type is null for property path " + propertyPath);

                if (String.IsNullOrEmpty(propertyPath))
                    throw new ArgumentException("propertyPath", "propertyPath cannot be null or empty for type " + rootType.FullName);

                int dotIdx = propertyPath.IndexOf('.');
                if (dotIdx <= 0)
                {
                    pi = rootType.GetProperty(propertyPath);
                    if (pi != null) return pi.PropertyType;
                    foreach (Type t in rootType.GetInterfaces())
                    {
                        pi = SafeGetProperty(t, propertyPath);
                        if (pi != null) return pi.PropertyType;
                    }
                    return typeof(Object);
                }

                String prop = propertyPath.Substring(0, dotIdx);
                pi = SafeGetProperty(rootType, prop);
                if (pi != null) return GetPropertyType(pi.PropertyType, propertyPath.Substring(dotIdx + 1));
                foreach (Type t in rootType.GetInterfaces())
                {
                    pi = SafeGetProperty(t, prop);
                    if (pi != null) break;
                }
                if (pi == null) return typeof(Object);
                return GetPropertyType(pi.PropertyType, propertyPath.Substring(dotIdx + 1));
            }

            public IList GetPropertiesArrayString(Type rootType)
            {
                IList propertyList = new ArrayList();
                PropertyInfo[] propertyInfos=  rootType.GetProperties(BindingFlags.Public |


                                                              BindingFlags.Static);
                for(int i=0 ; i < propertyInfos.Length;i++)
                    propertyList.Add(propertyInfos[0].Name);
                return propertyList;
            }
           
        
    }
}
